//
//  Copyright (c) 2012 Artyom Beilis (Tonkikh)
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef NOWIDE_CENV_H_INCLUDED
#    define NOWIDE_CENV_H_INCLUDED

#    include <nowide/config.hpp>
#    include <nowide/stackstring.hpp>
#    include <stdexcept>
#    include <stdlib.h>
#    include <string>
#    include <vector>

#    ifdef NOWIDE_WINDOWS
#        include <nowide/windows.hpp>
#    endif

namespace nowide
{
#    if !defined(NOWIDE_WINDOWS) && !defined(NOWIDE_DOXYGEN)
    using ::getenv;
    using ::putenv;
    using ::setenv;
    using ::unsetenv;
#    else
    ///
    /// \brief UTF-8 aware getenv. Returns 0 if the variable is not set.
    ///
    /// This function is not thread safe or reenterable as defined by the standard library
    ///
    inline char* getenv(char const* key)
    {
        static stackstring value;

        wshort_stackstring name;
        if (!name.convert(key)) return 0;

        static const size_t  buf_size = 64;
        wchar_t              buf[buf_size];
        std::vector<wchar_t> tmp;
        wchar_t*             ptr = buf;
        size_t               n   = GetEnvironmentVariableW(name.c_str(), buf, buf_size);
        if (n == 0 && GetLastError() == 203)    // ERROR_ENVVAR_NOT_FOUND
            return 0;
        if (n >= buf_size) {
            tmp.resize(n + 1, L'\0');
            n = GetEnvironmentVariableW(name.c_str(), &tmp[0], static_cast<unsigned>(tmp.size() - 1));
            // The size may have changed
            if (n >= tmp.size() - 1) return 0;
            ptr = &tmp[0];
        }
        if (!value.convert(ptr)) return 0;
        return value.c_str();
    }
    ///
    /// \brief  UTF-8 aware setenv, \a key - the variable name, \a value is a new UTF-8 value,
    ///
    /// if override is not 0, that the old value is always overridded, otherwise,
    /// if the variable exists it remains unchanged
    ///
    inline int setenv(char const* key, char const* value, int override)
    {
        wshort_stackstring name;
        if (!name.convert(key)) return -1;
        if (!override) {
            wchar_t unused[2];
            if (!(GetEnvironmentVariableW(name.c_str(), unused, 2) == 0 && GetLastError() == 203))    // ERROR_ENVVAR_NOT_FOUND
                return 0;
        }
        wstackstring wval;
        if (!wval.convert(value)) return -1;
        if (SetEnvironmentVariableW(name.c_str(), wval.c_str())) return 0;
        return -1;
    }
    ///
    /// \brief Remove enviroment variable \a key
    ///
    inline int unsetenv(char const* key)
    {
        wshort_stackstring name;
        if (!name.convert(key)) return -1;
        if (SetEnvironmentVariableW(name.c_str(), 0)) return 0;
        return -1;
    }
    ///
    /// \brief UTF-8 aware putenv implementation, expects string in format KEY=VALUE
    ///
    inline int putenv(char* string)
    {
        char const* key     = string;
        char const* key_end = string;
        while (*key_end != '=' && key_end != '\0') key_end++;
        if (*key_end == '\0') return -1;
        wshort_stackstring wkey;
        if (!wkey.convert(key, key_end)) return -1;

        wstackstring wvalue;
        if (!wvalue.convert(key_end + 1)) return -1;

        if (SetEnvironmentVariableW(wkey.c_str(), wvalue.c_str())) return 0;
        return -1;
    }
#    endif
}    // namespace nowide

#endif
///
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
